package com.med.meddataintegrator.jwt.utils;


import com.med.meddataintegrator.common.basic.exception.ServiceException;
import com.med.meddataintegrator.common.basic.response.StatusCode;
import io.jsonwebtoken.*;
import io.jsonwebtoken.security.Keys;
import lombok.extern.slf4j.Slf4j;
import org.mybatis.logging.Logger;
import org.mybatis.logging.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.crypto.SecretKey;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.Base64;
import java.util.Date;
import java.util.UUID;

@Slf4j
@Component
public class JwtUtil {
    // 密钥  静态变量无法通过该方式注入
    @Value("${jwt.secret}")
    public String SECRET;
    // 过期时间，单位：秒 默认是一天
    @Value("${jwt.expire}")
    public long EXPIRE = 24 * 60 * 60;
    // token前缀
    @Value("${jwt.tokenPrefix}")
    public static final String TOKEN_PREFIX = "Bearer ";
    // 拿到token的签发人
    @Value("${jwt.issuer}")
    private String ISSUER;

    /*
     * 实现日志的打印
     * */
    private static final Logger logger = LoggerFactory.getLogger(JwtUtil.class);

    /**
     * 获取唯一ID
     * @return UUID字符串，无连字符
     */
    public static String getUUID() {
        return UUID.randomUUID().toString().replace("-", "");
    }


    /**
     * 生成token
     * @param subject 需要存储导token中的数据  此处是根据用户名(账号)
     * @return
     */
    public  String createJwt(String subject) {
        if (subject == null || subject.trim().isEmpty()) {
            throw new IllegalArgumentException("Subject cannot be empty or null");
        }
        // 将数据 以及过期时间 以及唯一标识 生成token
        JwtBuilder jwt = getJwt(subject, EXPIRE, getUUID());
        return TOKEN_PREFIX + jwt.compact();
    }

    /**
     * 获取JwtBuilder 对象 生成token
     *
     * @param subject 主题内容
     * @param time    过期时间
     * @param uuid    唯一ID
     * @return JwtBuilder
     */
    private  JwtBuilder getJwt(String subject, long time, String uuid) {

        LocalDateTime now = LocalDateTime.now();
        LocalDateTime expiration = now.plusSeconds(time);

        //LocalDateTime 可以转为Date  时区是亚洲中国
        Date expirationDate = Date.from(expiration.atZone(ZoneId.systemDefault()).toInstant());
        Date nowDate = Date.from(now.atZone(ZoneId.systemDefault()).toInstant());
        log.info("token生成时间：{}", nowDate);
        log.info("token过期时间：{}", expirationDate);
        return Jwts.builder()
                .setId(uuid) // 唯一id
                .setSubject(subject) // 主题(数据内容)
                .setIssuedAt(nowDate) // 创建时间
                .setExpiration(expirationDate) // 过期时间
                .signWith(SignatureAlgorithm.HS256, SECRET) // 加密算法 SECRET 密钥
                .setIssuer(ISSUER); // 签发人
    }





    /**
     * 解析JWT Token
     *
     * @param token JWT Token
     * @return Claims对象
     * @throws IllegalArgumentException 如果token为空或null
     */
    public Jws<Claims> parseJwt(String token) {
        if (token == null || token.trim().isEmpty()) {
            throw new IllegalArgumentException("Token为空");
        }
        try {
            return Jwts.parser()
                    .setSigningKey(SECRET)
//                    先将前缀去掉
                    .parseClaimsJws(token.replace(TOKEN_PREFIX, ""));
        } catch (ExpiredJwtException e) {
            log.error("JWT令牌过期: {}", e.getMessage());
            throw new ServiceException(StatusCode.TOKEN_EXPIRE);
        } catch (Exception e) {
            log.error("Token反编译失败: {}", e.getMessage());
            throw new IllegalArgumentException("Token编译: Token反编译失败" + e.getMessage());
        }
    }


    /**
     * 获的Token中的subject内容
     *
     * @param token JWT Token
     * @return true/false
     */

    public  String getSubjectByToken(String token) {
        if (token == null || token.trim().isEmpty()) {
            throw new IllegalArgumentException("Token校验: Token为空");
        }

        Jws<Claims> claimsJws = parseJwt(token);
        String subject = claimsJws.getBody().getSubject();

        return subject;
    }


    /**
     * 生成一份密钥
     * @param args
     */

    public static void main(String[] args) {
        SecretKey key = Keys.secretKeyFor(io.jsonwebtoken.SignatureAlgorithm.HS256);
        String encodedKey = Base64.getEncoder().encodeToString(key.getEncoded());
        System.out.println("Generated Secret Key (Base64): " + encodedKey);
    }

}
